# coding: utf-8

from types import FunctionType, LambdaType


def sgn(val):
    if val == 0:
        return 0
    elif val > 0:
        return 1
    else:
        return -1


# 在原图的基础上将部分分支反向
def reverse_edges(dg, edges, reverse_func=None):
    # 查找要反向的分支
    seq = dg.es.select(edges)
    for e in seq:
        # 反向分支特殊处理,比如: 修改属性值
        if reverse_func and isinstance(reverse_func, FunctionType):
            reverse_func(dg, e)
        # 增加新的正方向分支(将原来负方向的分支属性完全复制过去)
        dg.add_edge(e.target, e.source, **e.attributes())
    # 删除原来的负方向分支
    dg.delete_edges(edges)


# 复制一份有向图及所有的节点、分支属性, 并转换为 有向图 或 无向图
# 注: 复制的图节点id与原图的节点id是一致的, 但分支id不一致!
def deep_copy(dg, directed=True, exclude_edges=[], bReverse=False):
    # 复制图
    g = None
    if directed:
        g = dg.as_directed()
    else:
        g = dg.as_undirected()

    if len(exclude_edges) > 0:
        # 删除要排除掉的分支
        g.delete_edges(get_real_edge_ids(dg, exclude_edges, g))

    # 复制分支属性
    # as_directed/as_undirected没有复制分支的属性, 需要人工复制分支的所有属性
    edge_attributes = dg.edge_attributes()
    for name in edge_attributes:
        for e in dg.es:
            i = g.get_eid(e.source, e.target, directed=False, error=False)
            if i >= 0:
                g.es[i][name] = e[name]

    # 如果是有向图复制, 并且bReverse=True, 则将分支反向
    # 具体做法: 添加反向分支, 然后删除正向分支
    if directed and bReverse:
        # 遍历所有的边
        edges = [e.index for e in g.es]
        for i in edges:
            e = g.es[i]
            # 添加反向边
            g.add_edge(e.target, e.source)
            j = g.es.indices[-1]
            # 复制完整的edge_attributes
            for name in edge_attributes:
                g.es[j][name] = e[name]
        # 删除正向边
        g.delete_edges(edges)

    return g


# 获取原图分支在新图中对应的id
# 参数:
#   dg -- 原图
#   edges -- 原图中的分支
#   new_dg -- 新图
def get_real_edge_ids(dg, edges, new_dg):
    _edges = []
    for i in edges:
        e = dg.es[i]
        j = new_dg.get_eid(e.source, e.target, directed=False, error=False)
        if j >= 0:
            _edges.append(j)
    return _edges


# 复制一个新图, 并将部分分支反向
# 参数:
#   dg -- 有向图
#   reverse_edges -- 要反向的分支数组(索引)
#   reverse_func -- 反向分支的回调函数
def copy_graph_and_reverse_edges(
    dg, exclude_edges=[], reverse_edges=[], reverse_func=None
):
    # 复制一个新的有向图
    g = deep_copy(dg, directed=True, exclude_edges=exclude_edges)
    # 获取原图分支在新图中的实际id, 并反向分支
    reverse_edges(g, get_real_edge_ids(dg, reverse_edges, g), reverse_func)
    # 返回有向图
    return g


def reverse_graph(dg, reverse_func=None, copy_graph=True):
    edges = [e.index for e in dg.es]
    g = dg
    if copy_graph:
        g = deep_copy(dg, directed=True)
        edges = get_real_edge_ids(dg, edges, g)
    reverse_edges(g, edges, reverse_func)
    return g


# judgment_value_is_Function_or_int


def is_callable(obj):
    return isinstance(obj, (FunctionType, LambdaType))


def try_run_func(f, args=None):
    if args is not None:
        try:
            return f(args)  # 先尝试有参
        except:
            return f()  # 再尝试无参
    else:
        return f()  # 无参


def try_get_value(value, args=None):
    if is_callable(value):
        return try_run_func(value, args)
    else:
        return value


def resize_list(arr, newsize, value=None):
    # print(newsize)
    if newsize > len(arr):
        # print(newsize)
        # for x in range(4, newsize):
        #     # print(x)
        #     arr.set(x, try_get_value(value))
        arr.extend([try_get_value(value) for x in range(len(arr), newsize)])
        # # for x in range(len(arr), newsize):
        #     arr.add_vertex
    # else:
    #     arr.delete_nodes(slice(newsize, None))


def find_list(arr, keyword):
    try:
        return arr.index(keyword)
    except ValueError:
        return -1
